﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using TL_Cloud.API.Helpers;
using TL_Cloud.Core.Entities;
using TL_Cloud.Core.Extensions;
using TL_Cloud.Core.Interfaces;
using TL_Cloud.Core.LinkURL;
using TL_Cloud.Core.Services;
using TL_Cloud.Models.BookShop;
using TL_Cloud.RepositoryInterface.BookShop;
using TL_Cloud.ViewModels.BookShop.BaseTeacher;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace TL_Cloud.API.Controllers
{
    /// <summary>
    /// 教师控制器
    /// </summary>
    [Route("api/[controller]")]
    [Authorize]
    [ApiController]
    public class TeachersController : Controller
    {
        private readonly ILogger logger;
        private readonly IUnitOfWork _unitOfWork;
        private readonly IBaseTeacherRepository _TeacherRepository;
        private readonly ITypeHelperService _typeHelperService;
        private readonly IPropertyMappingContainer _propertyMappingContainer = null;
        private readonly IMapper _mapper;
        private readonly IUrlHelper _urlHelper;

        public TeachersController(IMapper mapper,
            ILogger<TeachersController> logger,
            ITypeHelperService typeHelperService,
            IPropertyMappingContainer propertyMappingContainer,
            IBaseTeacherRepository TeacherRepository,
            IUnitOfWork unitOfWork,
            IUrlHelper urlHelper
            )
        {
            this._mapper = mapper;
            this.logger = logger;
            this._typeHelperService = typeHelperService;
            this._TeacherRepository = TeacherRepository;
            this._urlHelper = urlHelper;
            this._propertyMappingContainer = propertyMappingContainer;
            this._unitOfWork = unitOfWork;
        }
        /// <summary>
        /// 获取教师信息
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        [HttpGet(Name = "GetTeachers")]
        public async Task<IActionResult> Get([FromQuery]BaseTeacherQueryParameters parameters)
        {

            //判断排序是否存在 ，
            if (!_propertyMappingContainer.ValidateMappingExistsFor<BaseTeacherResource, Base_TeacherInfo>(parameters.OrderBy))
            {
                return BadRequest("Can't finds fields for sorting.");
            }

            //判断fields参数是否在制定的类型中存在
            if (!_typeHelperService.TypeHasProperties<BaseTeacherResource>(parameters.Fields))
            {
                return BadRequest("Fields not exist.");
            }

            var TeacherList = await _TeacherRepository.GetAllEntitiesAsync(parameters);

            var TeacherResources = _mapper.Map<IEnumerable<Base_TeacherInfo>, IEnumerable<BaseTeacherResource>>(TeacherList);

            //生成 下一个连接和上一个连接的url
            var previousPageLink = TeacherList.HasPrevious ?
                new LinkUrlCreater<BaseTeacherQueryParameters>(_urlHelper).CreateGetUrl("GetTeachers", parameters,
                    PaginationResourceUriType.PreviousPage) : null;

            var nextPageLink = TeacherList.HasNext ?
               new LinkUrlCreater<BaseTeacherQueryParameters>(_urlHelper).CreateGetUrl("GetTeachers", parameters,
                    PaginationResourceUriType.NextPage) : null;


            //数据返回分页数据
            var meta = new
            {
                TeacherList.TotalItemsCount,
                TeacherList.PageSize,
                TeacherList.PageIndex,
                TeacherList.PageCount,
                previousPageLink,
                nextPageLink
            };

            Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(meta, new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }));
            //返回结果塑性
            return Ok(TeacherResources.ToDynamicIEnumerable(parameters.Fields));
        }

        /// <summary>
        /// 获取单个教师数据
        /// </summary>
        /// <param name="id"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        [HttpGet("{id}", Name = "GetTeacher")]
        public async Task<IActionResult> Get(string id, string fields = null)
        {
            if (!_typeHelperService.TypeHasProperties<BaseTeacherResource>(fields))
            {
                return BadRequest("Fields not exist.");
            }
            var Teacher = await _TeacherRepository.GetEntityByIdAsync(id);

            if (Teacher == null)
            {
                return NotFound();
            }

            var TeacherResource = _mapper.Map<Base_TeacherInfo, BaseTeacherResource>(Teacher);
            var shapedTeacherResource = TeacherResource.ToDynamic(fields);
            var links = new LinkUrlCreater<BaseTeacherQueryParameters>(_urlHelper).CreateLinksForPost("GetTeacher", "DeleteTeacher", id, fields);
            var result = (IDictionary<string, object>)shapedTeacherResource;
            result.Add("links", links);

            return Ok(result);
        }

        /// <summary>
        /// 增加数据
        /// </summary>
        [HttpPost(Name = "CreateTeacher")]
        public async Task<IActionResult> Post([FromBody] BaseTeacherBasicInfoResource TeacherAddResource)
        {
            if (TeacherAddResource == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }

            var userInfo = this.GetUserInfo();
            var newTeacher = _mapper.Map<BaseTeacherBasicInfoResource, Base_TeacherInfo>(TeacherAddResource);

            newTeacher.Create(userInfo.Item1, userInfo.Item2);

            _TeacherRepository.Add(newTeacher);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception("Save Failed!");
            }

            var resultResource = _mapper.Map<Base_TeacherInfo, BaseTeacherResource>(newTeacher);

            var links = new LinkUrlCreater<BaseTeacherQueryParameters>(_urlHelper).CreateLinksForPost("GetTeacher", "DeleteTeacher", newTeacher.TeacherId);
            var linkedPostResource = resultResource.ToDynamic() as IDictionary<string, object>;
            linkedPostResource.Add("links", links);
            return CreatedAtRoute("GetTeacher", new { id = linkedPostResource["TeacherId"] }, linkedPostResource);
        }

        /// <summary>
        /// 修改数据
        /// </summary>
        /// <param name="id"></param> 
        [HttpPut("{id}", Name = "UpdateTeacher")]
        public async Task<IActionResult> UpdatePost(string id, [FromBody] BaseTeacherUpdateResource TeacherUpdate)
        {
            if (TeacherUpdate == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }

            var Teacher = await _TeacherRepository.GetEntityByIdAsync(id);
            if (Teacher == null)
            {
                return NotFound();
            }
            var userInfo = this.GetUserInfo();
            _mapper.Map(TeacherUpdate, Teacher);
            Teacher.Modify(userInfo.Item1, userInfo.Item2);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Updating Teacher {id} failed when saving.");
            }
            return NoContent();
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}", Name = "DeleteTeacher")]
        public async Task<IActionResult> DeleteTeacher(string id)
        {
            var post = await _TeacherRepository.GetEntityByIdAsync(id);
            if (post == null)
            {
                return NotFound();
            }

            _TeacherRepository.Delete(post);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Deleting Teacher {id} failed when saving.");
            }

            return NoContent();
        }
    }
}
